<script setup lang="ts" name="GoodsSku">
import { GoodsInfo, specsItem, valuesItem } from '@/types/data';
import bwPowerSet from '@/utils/bwPowerSet'
const props =  defineProps<{
  goods: GoodsInfo
  skuId?: string
}>() 

const emit = defineEmits<{
  (e: 'changeSku', skuId: string): void
}>()

const sep = '+'

const changeSelected = (sub: valuesItem, item: specsItem) => {
  // 判断如果被禁用了就不要选中
  if(sub.disabed) return
  // 干掉所有人(排除自己)
  item.values.filter(v => v.name !== sub.name).forEach(i => i.selected = false)
  // 修改当前被点击的属性 selected 取反
  sub.selected = !sub.selected
  // 调用 updateDisabledStatus
  // 更新组合规格的禁用状态
  // 该调用必须在排他结束后执行
  updatedDisabledStatus()

  // 获取当前选中的规格
  // 判断是否选中了所有规格, 如果选中了就子传父将 skuId 传过去
  const result =  getSelectedSpec()
  // 方案一
  const isAll = result.every(item => item)
  // 方案二
  // result.filter(i => i).length === props.goods.specs.length
  if(isAll) {
    // 如何获取 skuId 给父组件
    const key = result.join(sep)
    const val = pathMap[key]    
    emit('changeSku', val[0])
  }
}

// const result = bwPowerSet(['田', '勇', '正'])
// console.log(result)

// 目标: 生成路径字典
function getPathMap() {
  // 1.筛选无效的数据(没有库存的)
  const skus = props.goods.skus.filter(item => item.inventory > 0)
  // 创建一个映射对象 (路径字典)
  const pathMap: any = {}
  // 2. 将 sku 转成字符串数组 
  // 算法要的是数组 => 将对象数组转成字符串数组
  skus.forEach(item => {
    const arr = item.specs.map(v => v.valueName)

    // 3.调用算法生成子集
    const result = bwPowerSet(arr)
    // 4.s往路径字典对象中添加属性
    result.forEach(arrItem => {
      // 4.1 如果对象中没有这个属性, 就创建一个数组, 添加 id
      // 4.2 如果有这个属性, 直接添加 id 到数组
      const key = arrItem.join('+')
        if (key in pathMap) {
        // 4.2 如果对象中有这个属性, 就直接添加 id 到数组
        pathMap[key].push(item.id)
      } else {
        // 4.1 如果对象中没有这个属性, 就创建一个数组, 添加 id
        // const arr = [1, 2, 3, 4, item.id]
        pathMap[key] = [item.id]
        // pathMap[key].push(item.id)
      }
    })
  })
  return pathMap
}

// 修改禁用状态, 页面加载时就对所有元素进行修改
function updatedDisabledStatus() {
  // 该方法的作用: 循环所有 specs(规格) 去路径字典里找, 是否存在
  // 如果存在就不禁用, 如果不存在就禁用
  props.goods.specs.forEach((item, index) => {
    item.values.forEach(sub => {

      // 去对象里找是否有这个属性, 该怎么做? key in obj 得到布尔值
      // 如果存在就不禁用, 如果不存在就禁用
      // if(sub.name in pathMap) {
      //   sub.disabed = false
      // } else{
      //   sub.disabed = true
      // }
      // 先获取所有选中商品规格
      const selectedArr = getSelectedSpec()
      selectedArr[index] = sub.name
      // console.log(selectedArr, sub.name, index)
      const key = selectedArr.filter(v => v).join(sep) 
      // 只要是将 if 条件表达式的结果赋值给某个对象, 都可以用这种办法: 直接将条件表达式赋给对象的属性
      // 开发小技巧
      sub.disabed = !(key in pathMap)
    })
  })
}

// 获取被选中的规格
function getSelectedSpec() {
  // 希望获取每个规格被选中的值
  const arr: string[] = []
  // 遍历所有的规格, 获取选中状态
  props.goods.specs.forEach(item => {
    const result = item.values.find(v => v.selected)
    arr.push(result?.name || '')
  })
  return arr
}

// 初始化勾选状态
function initSpecSeletcted() {
  if(!props.skuId) return
  // 通过 skuId 去找当前 sku 勾选的规格
  const result = props.goods.skus.find(item => item.id === props.skuId)
  if(!result) return
  // 遍历所有的规格, 处理选中状态
  const selectArr = result.specs.map(item => item.valueName)
  props.goods.specs.forEach(item => {
    item.values.forEach(sub => {
      sub.selected = selectArr.includes(sub.name)
    })
  })
}
// 1. 获取路径字典
const pathMap = getPathMap()

// 2. 初始化勾选状态
initSpecSeletcted()
// 3. 更新禁用状态
updatedDisabledStatus()
</script>

<template>
  <div class="goods-sku">
    <dl v-for="item in goods.specs" :key="item.name">
      <dt>{{ item.name }}</dt>
      <dd>
        <template v-for="sub in item.values" :key="sub.name">
          <img
            @click="changeSelected(sub, item)"
            v-if="sub.picture"
            :class="{selected: sub.selected, disabled: sub.disabed}"
            :src="sub.picture"
            alt=""
          />
        <span v-else 
        :class="{selected: sub.selected, disabled: sub.disabed}" 
        @click="changeSelected(sub, item)"
        >{{ sub.name }}
        </span>
       </template>
      </dd>
    </dl>
  </div>
</template>

<style scoped lang="less">
.sku-state-mixin () {
  border: 1px solid #e4e4e4;
  margin-right: 10px;
  cursor: pointer;
  &.selected {
    border-color: @xtxColor;
  }
  &.disabled {
    opacity: 0.6;
    border-style: dashed;
    cursor: not-allowed;
  }
}
.goods-sku {
  padding-left: 10px;
  padding-top: 20px;
  dl {
    display: flex;
    padding-bottom: 20px;
    align-items: center;
    dt {
      width: 50px;
      color: #999;
    }
    dd {
      flex: 1;
      color: #666;
      > img {
        width: 50px;
        height: 50px;
        margin-top: 5px;
        .sku-state-mixin ();
      }
      > span {
        display: inline-block;
        height: 30px;
        line-height: 30px;
        padding: 0 20px;
        margin-top: 5px;
        .sku-state-mixin ();
      }
    }
  }
}
</style>
